package com.panfeng.xcloud.boss.provider.member.security.verifyCode;

import com.panfeng.xcloud.boss.provider.member.cache.CacheContext;
import com.panfeng.xcloud.common.core.configuration.DataDictionaryConfig;
import com.panfeng.xcloud.common.core.constants.Constants;
import com.panfeng.xcloud.common.core.enums.DataDictionaryTypeEnum;
import com.panfeng.xcloud.common.core.enums.ResponseStatusEnum;
import com.panfeng.xcloud.common.core.enums.VerifiyCodeTypeEnum;
import com.panfeng.xcloud.common.core.exceptions.BaseBizException;
import com.panfeng.xcloud.common.core.utils.MD5Utils;
import com.panfeng.xcloud.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;

/**
 *
 * 短信验证码-登录验证提供者
 *
 * @author xiaobo
 * @version 1.0
 * @since 2018-12-28
 */
@Slf4j
public class VerifyCodeAuthenticationProvider implements AuthenticationProvider {

	private UserDetailsService userDetailsService;

	private CacheContext cacheContext;

	private DataDictionaryConfig dataDictionaryConfig;

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		log.info(">>>> 开始执行VerifyCodeAuthenticationProvider鉴权提供者，查询认证用户信息 <<<");
		VerifyCodeAuthenticationToken authenticationToken = (VerifyCodeAuthenticationToken) authentication;
		//格式：grantType + "_" + mobile + "_" + verifyCode +"_"+ clientId +"_" + clientSecret
		String principal = (String) authenticationToken.getPrincipal();
		log.info(">>>> 执行VerifyCodeAuthenticationProvider鉴权提供者，principal信息：{} <<<",principal);
		UserDetails user = userDetailsService.loadUserByUsername(principal);
		if (user == null) {
			log.error(">>>> 执行VerifyCodeAuthenticationProvider鉴权提供者异常：无法获取用户信息 <<<");
			throw new BaseBizException(ResponseStatusEnum.LOGIN_USER_IS_NOT_EXIST_ERROR);
		}
		String verifyCodeSwitch = dataDictionaryConfig.getCodeToNameMap().get(DataDictionaryTypeEnum.verify_code_switch.getCode());
		verifyCodeSwitch = !StringUtils.isEmpty(verifyCodeSwitch) ? verifyCodeSwitch : "false";
		if("true".equalsIgnoreCase(verifyCodeSwitch)){
			log.info(">>>>已开启内部短信验证机制 <<<<");
			if (!MD5Utils.digest(Constants.TEST_VERIFY_CODE).equals(user.getPassword())) {
				log.error(">>>> 执行VerifyCodeAuthenticationProvider鉴权提供者异常：验证码输入不正确-内部验证码 <<<");
				//throw new BaseBizException(ResponseStatusEnum.VERIFYCODE_INPUT_ERROR);
				throw new InternalAuthenticationServiceException("验证码输入不正确");
			}
		}else{
			String cacheVerifyCode = cacheContext.getVerifyCodeByMobileNo(user.getUsername(), VerifiyCodeTypeEnum.LOGIN);
			String digestCacheVerifyCode = StringUtils.isEmpty(cacheVerifyCode) ? "" : MD5Utils.digest(cacheVerifyCode);
			if(StringUtils.isEmpty(cacheVerifyCode) || !digestCacheVerifyCode.equals(user.getPassword())){
				log.error(">>>> 执行VerifyCodeAuthenticationProvider鉴权提供者异常：验证码输入不正确-外部验证码 <<<");
				//throw new BaseBizException(ResponseStatusEnum.VERIFYCODE_INPUT_ERROR);
				throw new InternalAuthenticationServiceException("验证码输入不正确");
			}
			cacheContext.clearVerifyCodeCacheByMobileNo(user.getUsername(), VerifiyCodeTypeEnum.LOGIN);
		}

		//重新生成principal，由mobileNo转化成UserDetails
		VerifyCodeAuthenticationToken authenticationResult = new VerifyCodeAuthenticationToken(user,user.getAuthorities());
		authenticationResult.setDetails(authenticationToken.getDetails());
		return authenticationResult;
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return VerifyCodeAuthenticationToken.class.isAssignableFrom(authentication);
	}

	public UserDetailsService getUserDetailsService() {
		return userDetailsService;
	}

	public void setUserDetailsService(UserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}

	public CacheContext getCacheContext() {
		return cacheContext;
	}

	public void setCacheContext(CacheContext cacheContext) {
		this.cacheContext = cacheContext;
	}

	public DataDictionaryConfig getDataDictionaryConfig() {
		return dataDictionaryConfig;
	}

	public void setDataDictionaryConfig(DataDictionaryConfig dataDictionaryConfig) {
		this.dataDictionaryConfig = dataDictionaryConfig;
	}
}
